
#pragma once

#include <ConnectionBroker/TcpMessage.h>
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/cstdint.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/shared_ptr.hpp>


namespace ConnectionBroker
{
   class TcpConnection : public boost::enable_shared_from_this<TcpConnection>
   {
      protected: //Member variables
      TcpMessage mReadMessage;
      std::deque<TcpMessage> mWriteMessages;
      boost::shared_ptr<boost::asio::ip::tcp::socket> mSocket;
      boost::shared_ptr<boost::asio::ssl::stream<boost::asio::ip::tcp::socket> > mSslSocket;
      boost::asio::io_service& mIoService;
      bool mStopping;
      bool mUsingSsl;
      //char mSslReadMessage[MAX_SSL_LENGTH];
      bool mClientMode;
      boost::mutex mMutex;


      public: //Constructor, destructor
      TcpConnection(bool clientMode, boost::asio::io_service& pIoService, boost::shared_ptr<boost::asio::ssl::context> pContext);
      virtual ~TcpConnection();

      public: //Getters
      const bool clientMode() const { return mClientMode; }
      const bool usingSsl() const { return mUsingSsl; }
      boost::asio::ssl::stream<boost::asio::ip::tcp::socket>::lowest_layer_type& sslSocket() const { return mSslSocket->lowest_layer(); }
      boost::asio::ip::tcp::socket& socket() { return *mSocket; }

      public: //Interface
      virtual void start();
      virtual void stop();
      virtual void send(const ConnectionBroker::Packet& pPacket);
      void setVerifyFilepath(const std::string& filepath);

      protected: //Pure virtual interface
      virtual void messageReceived(const Packet& pMessage) = 0;

      protected: //Utilities
      void         asyncHandshake();
      void         asyncWrite(const TcpMessage& msgTcp);
      void         asyncConnect(const std::string& address, const unsigned short port);
      void         asyncReadSsl();
      void         asyncReadHeader();
      void         asyncReadBody();
      virtual void connectionEstablished();
      virtual void onStop();
      void         doWrite(Packet msg);
      void         handleConnect(const boost::system::error_code& error);
      void         handleHandshake(const boost::system::error_code& error);
      void         handleReadBody(const boost::system::error_code& error);
      void         handleReadHeader(const boost::system::error_code& error);
      void         handleReadSsl(const boost::system::error_code& error);
      virtual void handleWrite(const boost::system::error_code& error);
   }; 
}

